/* see: https://github.com/moon-chilled/Defer */
#ifndef _DEFER_H__
#define _DEFER_H__

#ifndef DEFER_MAX_DEFERRED_STATEMENTS
#	define DEFER_MAX_DEFERRED_STATEMENTS 0x10
#endif

#include <setjmp.h>

#include "util.h"

#define Deferral                                                              \
	volatile unsigned char _num_deferrals__		    = 0;              \
	jmp_buf		       _defer_return_loc__	    = { 0 };          \
	jmp_buf _deferrals__[DEFER_MAX_DEFERRED_STATEMENTS] = { 0 }

#define Defer(block)                                                          \
	if (setjmp(_deferrals__[_num_deferrals__++])) {                       \
		block;                                                        \
		if (_num_deferrals__)                                         \
			longjmp(_deferrals__[--_num_deferrals__], !0);        \
                                                                              \
		else                                                          \
			longjmp(_defer_return_loc__, !0);                     \
	}                                                                     \
	(void)0

#define Return                                                                \
	if (!setjmp(_defer_return_loc__)) {                                   \
		if (_num_deferrals__)                                         \
			longjmp(_deferrals__[--_num_deferrals__], !0);        \
		UNREACHABLE();                                                \
	} else                                                                \
		return

#endif /* _DEFER_H__ */
